from django.core.validators import FileExtensionValidator
from django.core.exceptions import ValidationError
from django.conf import settings
from django.db import models
from datetime import date  # 需要导入date模块
from rbac.models import UserInfo as RbacUserInfo
from decimal import ROUND_HALF_UP  # Decimal


# 一、基础信息模块
class CityArea(models.Model):
    id = models.AutoField(primary_key=True, verbose_name="主键")
    city_name = models.CharField(max_length=50, verbose_name="城市名称")
    area_name = models.CharField(max_length=50, verbose_name="区域名称")
    
    class Meta:
        verbose_name = "城市/区域表"
        verbose_name_plural = verbose_name
    
    def __str__(self):
        return f"{self.city_name}-{self.area_name}"


class User(RbacUserInfo):
    phone = models.CharField(max_length=20, unique=True, verbose_name="手机号")
    city_area = models.ForeignKey(
        CityArea,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name="所在城市区域"
    )
    
    class Meta:
        verbose_name = "用户信息表"
        verbose_name_plural = verbose_name
    
    def __str__(self):
        # return f"{self.name}"
        return self.name


# 二、房源核心模块
class House(models.Model):
    landlord_id = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="房东", limit_choices_to={'roles__title': "房东"})
    city_area_id = models.ForeignKey(CityArea, on_delete=models.CASCADE, verbose_name="城市区域")
    room_number = models.CharField(max_length=10, verbose_name="房号")
    address = models.CharField(max_length=200, verbose_name="详细地址")
    house_type = models.CharField(max_length=50, verbose_name="户型", blank=True, null=True)
    area_size = models.CharField(max_length=50, verbose_name="面积", blank=True, null=True)
    rent_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="每月租金", blank=True, null=True)
    deposit = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="押金", blank=True, null=True)
    facilities = models.TextField(verbose_name="配套设施", blank=True, null=True)
    status = models.CharField(
        max_length=20,
        choices=[
            ("1", "空房"),  # 改为元组
            ("2", "已租")
        ],
        default="1",
        verbose_name="房源状态"
    )
    description = models.TextField(verbose_name="房源描述", blank=True, null=True, )
    # 新增：图片上传字段
    cover_image = models.ImageField(
        upload_to='images/houses/%Y/%m/%d/',
        verbose_name='房屋封面图',
        null=True,
        blank=True,
        validators=[
            FileExtensionValidator(allowed_extensions=settings.ALLOWED_UPLOAD_EXTENSIONS),
        ]
    )
    images = models.TextField(verbose_name="房源图片路径", blank=True, null=True, )
    
    class Meta:
        verbose_name = "房源表"
        verbose_name_plural = verbose_name

    def get_status(self):
        """动态获取房源状态：优先取有效合同，否则为空房"""
        # 反向查询该房源的所有合同，过滤出“有效”的合同
        valid_contracts = self.contract_set.filter(status="1")
        return "已租" if valid_contracts.exists() else "空房"

    def update_status_to_db(self):
        """将get_status的结果更新到数据库"""
        # 调用get_status计算最新状态
        new_status = self.get_status()
        # 如果状态有变化才更新（可选优化）
        if self.status != new_status:
            self.status = new_status
            self.save(update_fields=["status"])  # 只更新status字段，提高效率
        return new_status

    def __str__(self):
        return f"{self.room_number}-{self.landlord_id}"


# 三、合同模块
class Contract(models.Model):
    """ 合同表 """
    house = models.ForeignKey(House, on_delete=models.CASCADE, verbose_name="房源", limit_choices_to={})
    tenant_id = models.ForeignKey(User, related_name="tenant_contracts", on_delete=models.CASCADE, verbose_name="租户", limit_choices_to={'roles__title': "租户"})
    landlord_id = models.ForeignKey(User, related_name="landlord_contracts", on_delete=models.CASCADE, verbose_name="房东", limit_choices_to={'roles__title': "房东"})
    start_date = models.DateField(verbose_name="起租日", blank=True, null=True, default=date.today)  # 自动填充当前日期
    end_date = models.DateField(verbose_name="到期日", null=True, blank=True)

    total_rent = models.DecimalField(max_digits=12, decimal_places=2, verbose_name="合同期租金")
    water_price = models.DecimalField(max_digits=8, decimal_places=2, default=6, verbose_name="水费单价")
    electricity_price = models.DecimalField(max_digits=8, decimal_places=2, default=1.2, verbose_name="电费单价")
    gas_price = models.DecimalField(max_digits=8, decimal_places=2, default=3, verbose_name="燃气费单价")
    status = models.CharField(
        max_length=20,
        choices=[
            ("1", "有效"),  # 改为元组
            ("2", "已到期"),
            ("3", "已解约")
        ],
        default="1",
        verbose_name="合同状态",
        blank=True,
        null=True
    )
    
    class Meta:
        verbose_name = "租赁合同表"
        verbose_name_plural = verbose_name
    
    def __str__(self):
        return f"{self.house} 与 {self.tenant_id} 的合同"

   
# 四、辅助管理模块
class MeterReading(models.Model):
    house = models.ForeignKey(House, on_delete=models.CASCADE, verbose_name="房源")
    meter_type = models.CharField(
        max_length=20,
        choices=[
            ("1", "电表"),
            ("2", "水表"),
            ("3", "燃气表")
        ],
        default="1",
        verbose_name="表类型",
        blank=True,
        null=True
    )
    reading_date = models.DateField(verbose_name="抄表日期")
    previous_reading = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="上次读数", null=True, blank=True)
    current_reading = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="本次读数")
    consumption = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0,
        verbose_name="本期用量",
        blank=True
    )
    
    def clean(self):
        # 检查同一房源、同一类型的表在同一月份是否已有记录
        if MeterReading.objects.filter(
            house=self.house,
            meter_type=self.meter_type,
            reading_date__year=self.reading_date.year,
            reading_date__month=self.reading_date.month
        ).exclude(id=self.id if self.id else None).exists():
            raise ValidationError({
                'reading_date': f'该房源的{self.get_meter_type_display()}在{self.reading_date.year}年{self.reading_date.month}月已有记录，每月只能记录一次'
            })
    
    def save(self, *args, **kwargs):
        # 先执行验证
        self.full_clean()
        
        # 自动获取上次读数
        if not self.id:
            last_reading = MeterReading.objects.filter(
                house=self.house,
                meter_type=self.meter_type
            ).order_by('-reading_date').first()
            
            self.previous_reading = last_reading.current_reading if last_reading else 0
        
        # 计算本期用量

        self.consumption = self.current_reading - self.previous_reading
        
        super().save(*args, **kwargs)
    
    class Meta:
        verbose_name = "抄表记录"
        verbose_name_plural = verbose_name
        unique_together = ("house", "meter_type", "reading_date")  # 保持日期唯一约束
    
    def __str__(self):
        return f"{self.get_meter_type_display()}抄表（{self.reading_date}）"


# 租金账单表模块
class RentBill(models.Model):
    """租金账单表"""
    contract = models.ForeignKey(Contract, on_delete=models.CASCADE, verbose_name="合同")
    bill_month = models.CharField(max_length=7, verbose_name="账单所属月份")  # 格式：YYYY-MM
    rent_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="当月应收租金", null=True, blank=True)

    # 用量字段（从抄表记录自动获取，可不手动输入）
    water_usage = models.DecimalField(max_digits=10, decimal_places=2, default=0,  verbose_name="水费用量(吨)", null=True, blank=True)
    electricity_usage = models.DecimalField(max_digits=10, decimal_places=2, default=0,  verbose_name="电费用量(度)", null=True, blank=True)
    gas_usage = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name="燃气用量(立方米)", null=True, blank=True)

    # 费用字段（自动计算）
    water_fee = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name="水费金额", null=True, blank=True)
    electricity_fee = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name="电费金额", null=True, blank=True)
    gas_fee = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name="燃气费金额", null=True, blank=True)
    total_fee = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name="总费用(含租金)", null=True, blank=True)

    paid_status = models.CharField(
        max_length=20,
        choices=[("1", "待收"), ("2", "已收")],
        default="1",
        verbose_name="支付状态"
    )
    paid_date = models.DateField(null=True, blank=True, verbose_name="支付日期")

    class Meta:
        verbose_name = "租金账单表"
        verbose_name_plural = verbose_name
        unique_together = ("contract", "bill_month")  # 同一合同同一月份唯一

    # def get_meter_usage(self):
    #     """从抄表记录中获取当月用量"""
    #     # 1. 通过合同关联到房源
    #     house = self.contract.house
    #
    #     # 2. 解析账单月份
    #     try:
    #         year, month = self.bill_month.split('-')
    #         year = int(year)
    #         month = int(month)
    #     except (ValueError, AttributeError) as e:
    #         print(f"解析账单月份失败: {e}, bill_month值: {self.bill_month}")
    #         return
    #
    #     # 3. 获取当月的抄表记录
    #     # 电表（类型1）
    #     electricity_reading = MeterReading.objects.filter(
    #         house=house,
    #         meter_type="1",
    #         reading_date__year=year,
    #         reading_date__month=month
    #     ).first()
    #
    #     # 水表（类型2）
    #     water_reading = MeterReading.objects.filter(
    #         house=house,
    #         meter_type="2",
    #         reading_date__year=year,
    #         reading_date__month=month
    #     ).first()
    #
    #     # 燃气表（类型3）
    #     gas_reading = MeterReading.objects.filter(
    #         house=house,
    #         meter_type="3",
    #         reading_date__year=year,
    #         reading_date__month=month
    #     ).first()
    #
    #     # 添加调试信息
    #     print(f"房屋: {house.id}, 月份: {self.bill_month}")
    #     print(f"电表记录: {'存在' if electricity_reading else '不存在'}")
    #     print(f"水表记录: {'存在' if water_reading else '不存在'}")
    #     print(f"燃气表记录: {'存在' if gas_reading else '不存在'}")
    #
    #     # 4. 更新用量，确保即使没有记录也有默认值0
    #     self.electricity_usage = electricity_reading.consumption if electricity_reading else 0
    #     self.water_usage = water_reading.consumption if water_reading else 0
    #     self.gas_usage = gas_reading.consumption if gas_reading else 0
    #
    def get_meter_usage(self):
        """从抄表记录中获取当月用量（不依赖reading_month字段）"""
        # 1. 通过合同关联到房源
        house = self.contract.house

        # 2. 解析账单月份（假设格式为YYYY-MM）
        year, month = self.bill_month.split('-')
        year = int(year)
        month = int(month)
        # 3. 获取当月的抄表记录（通过日期提取年份和月份）
        # 电表（类型1）
        electricity_reading = MeterReading.objects.filter(
            house=house,
            meter_type="1",  # 电表
            # 使用日期函数提取年份和月份进行匹配
            reading_date__year=year,
            reading_date__month=month
        ).first()

        # 水表（类型2）
        water_reading = MeterReading.objects.filter(
            house=house,
            meter_type="2",  # 水表
            reading_date__year=year,
            reading_date__month=month
        ).first()

        # 燃气表（类型3）
        gas_reading = MeterReading.objects.filter(
            house=house,
            meter_type="3",  # 燃气表
            reading_date__year=year,
            reading_date__month=month
        ).first()

        # 4. 更新用量
        if electricity_reading:
            self.electricity_usage = electricity_reading.consumption
        if water_reading:
            self.water_usage = water_reading.consumption
        if gas_reading:
            self.gas_usage = gas_reading.consumption
    
    def calculate_usage_fee(self):
        """计算费用（不主动调用save，仅更新字段值）"""
        self.get_meter_usage()
    
        # 从合同获取单价（确保Decimal类型）
        from decimal import Decimal
        water_price = self.contract.water_price or Decimal('5.00')
        electricity_price = self.contract.electricity_price or Decimal('0.56')
        gas_price = self.contract.gas_price or Decimal('3.00')
    
        # 计算费用并强制保留2位小数（四舍五入）
        self.water_fee = (self.water_usage * water_price).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
        self.electricity_fee = (self.electricity_usage * electricity_price).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
        self.gas_fee = (self.gas_usage * gas_price).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
    
        # 总费用同样处理
        self.total_fee = (self.contract.total_rent + self.water_fee + self.electricity_fee + self.gas_fee).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
        self.rent_amount = self.total_fee
        
    def save(self, *args, **kwargs):
        """重写save方法，避免无限递归"""
        # 1. 先计算费用（仅更新字段，不保存）
        self.calculate_usage_fee()
    
        # 2. 调用父类save方法（仅一次，不再次触发当前save）
        # 关键点：使用super()调用原始save，不传入可能触发递归的参数
        super(RentBill, self).save(*args, **kwargs)

    def __str__(self):
        return f"{self.contract.tenant_id}在{self.bill_month}月账单"


# 五 提醒模块
class Reminder(models.Model):
    """ 提醒表 """
    reminder_type = models.CharField(
        max_length=20,
        choices=[
            ("1", "合同到期"),  # 改为元组
            ("2", "租金待收")
        ],
        verbose_name="提醒类型"
    )
    reminder_content = models.ForeignKey(RentBill, max_length=500, verbose_name="提醒内容", on_delete=models.CASCADE)
    remind_date = models.DateField(verbose_name="提醒触发日期")
    is_processed = models.CharField(
        max_length=20,
        choices=[
            ("1", "未处理"),  # 改为元组
            ("2", "已处理")
        ],
        default="1",
        verbose_name="是否已处理",
        blank=True,
        null=True
    )
    
    class Meta:
        verbose_name = "提醒表"
        verbose_name_plural = verbose_name
    
    def __str__(self):
        return self.reminder_content
